package OrderService

import (
	"context"
	"errors"
	"gdshop-font-api-go/app/entity"
	"gdshop-font-api-go/app/request/OrderReq"
	"gdshop-font-api-go/app/response/GoodsResp"
	"gdshop-font-api-go/app/response/MemberResp"
	"gdshop-font-api-go/app/response/OrderResp"
	"gdshop-font-api-go/app/service/CouponService"
	"gdshop-font-api-go/app/service/GoodsService"
	"gdshop-font-api-go/library/tools"
	toolsDb "gdshop-font-api-go/library/tools/db"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
	"github.com/gogf/gf/util/guid"
	"github.com/gogf/gf/util/gvalid"
	"github.com/syyongx/php2go"
	"strings"
)

// 检查goods，单条检测
func checkGoods(ctx context.Context, parames *OrderReq.GoodsItem, storeId int) (*OrderReq.OrderSubItem, error) {
	// 判断基本参数
	rules := map[string]string{
		"GoodsId":       "required|integer|min:1",
		"GoodsOptionId": "required|integer|min:1",
		"GoodsNum":      "required|integer|min:1",
	}
	msgs := map[string]interface{}{
		"GoodsId": map[string]string{
			"required": "请选择商品",
			"integer":  "商品ID格式错误",
			"min":      "商品ID格式错误",
		},
		"GoodsOptionId": map[string]string{
			"required": "请选择商品规格",
			"integer":  "商品规格ID格式错误",
			"min":      "商品规格ID格式错误",
		},
		"GoodsNum": map[string]string{
			"required": "请填写商品数量",
			"integer":  "商品数量格式错误",
			"min":      "数量不能小于1",
		},
	}

	if e := gvalid.CheckStruct(ctx, parames, rules, msgs); e != nil {
		//g.Dump(e.Maps())
		return nil, e
	}

	// 先找出是否有当前商品
	goodsModel := GoodsService.GetGoodsModelRaw(ctx, parames.GoodsId)
	if goodsModel == nil {
		return nil, errors.New("找不到goods数据，ID：" + gconv.String(parames.GoodsId))
	}
	// 检测店铺ID是否相等
	if goodsModel.StoreId != storeId {
		return nil, errors.New("店铺ID不相等，ID：" + gconv.String(parames.GoodsId))
	}
	// 判断是否是上架状态
	if goodsModel.Status != 1 {
		return nil, errors.New("商品《" + goodsModel.GoodsName + "》已下架")
	}
	optionModel := GoodsService.GetGoodsOptionsById(ctx, int(parames.GoodsOptionId))
	if optionModel == nil {
		return nil, errors.New("找不到goods_option数据，ID：" + gconv.String(parames.GoodsOptionId))
	}

	// 判断当前规格是否指向当前商品
	if optionModel.GoodsId != int(goodsModel.Id) {
		g.Log().Error("GoodsId:" + gconv.String(goodsModel.Id) + " optionModel:" + gconv.String(optionModel))
		return nil, errors.New("GoodsId不匹配，ID：" + gconv.String(parames.GoodsOptionId))
	}

	// 数量是否超库存
	if parames.GoodsNum > optionModel.Stock {
		g.Log().Error("GoodsNum:" + gconv.String(parames.GoodsNum) + " optionModel:" + gconv.String(optionModel))
		return nil, errors.New("《" + optionModel.Title + "》规格库存不足")
	}
	// 压入规则规格
	goodsModel.Options = []*GoodsResp.GoodsOption{}
	goodsModel.Options = append(goodsModel.Options, optionModel)

	orderSubItem := OrderReq.OrderSubItem{
		Total: parames.GoodsNum,
		// 先计算出总价，后面不再计算
		TotalPrice: optionModel.SellPrice * int64(parames.GoodsNum),
		Details:    *goodsModel,
	}
	// 2021.07.17 增加数据标识符
	orderSubItem.SellPrice = optionModel.SellPrice
	orderSubItem.Hash = guid.S()
	orderSubItem.CategoryId = getCategoryIds(orderSubItem.Cates)
	orderSubItem.OptionId = int(optionModel.Id)

	// 2021.09.13 计算活动价格

	return &orderSubItem, nil
}
func getCategoryIds(cates string) []int {
	tmps := strings.Split(strings.Trim(cates, ","), ",")
	var fanhui []int
	for _, item := range tmps {
		fanhui = append(fanhui, gconv.Int(item))
	}
	return fanhui
}
func getGoodsKeyString(GoodsList []*OrderReq.OrderSubItem) string {
	var str []string
	for _, goods := range GoodsList {
		str = append(str, goods.GoodsName)
	}
	return strings.Join(str, "-")
}

// OrderSubItemModelToOrderSubCoupon model 转换
func OrderSubItemModelToOrderSubCoupon(item *OrderReq.OrderSubItem, couponId, memberCouponId int) OrderReq.OrderSubCoupon {
	return OrderReq.OrderSubCoupon{
		Hash:           item.Hash,
		StoreId:        item.StoreId,
		GoodsId:        int(item.Id),
		Price:          item.SellPrice,
		Num:            int64(item.Total),
		TotalPrice:     item.TotalPrice,
		CouponId:       couponId,
		MemberCouponId: memberCouponId,
		GoodsOptionId:  item.OptionId,
	}
}

// 计算单张优惠券使用的结果，返回已使用的结果
func calcCouponOne(orderSubs []*OrderReq.OrderSubItem,
	coupon *MemberResp.MemberCoupon) []OrderReq.OrderSubCoupon {
	var ids []int
	// 防止修改状态
	ids = coupon.UseSrcIdsIntArr

	// 先保存下可使用的子订单
	var canUseOrderSubs []OrderReq.OrderSubCoupon
	// 适用商品类型 0全部可用 1指定分类可用 2指定分类不可用 3指定商品可用 4指定商品不可用 5指定店铺可用 6指定店铺不可用
	for _, item := range orderSubs {
		if coupon.UseGoodsType == 0 { // 全部可用
			canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
			continue
		}
		if coupon.UseGoodsType == 1 { // 1指定分类可用
			for _, cid := range item.CategoryId {
				if php2go.InArray(cid, ids) {
					//  包含在可用里面
					canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				}
			}
			continue
		}
		if coupon.UseGoodsType == 2 { // 2指定分类不可用
			for _, cid := range item.CategoryId {
				if !php2go.InArray(cid, ids) {
					//  包含在可用里面
					canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				}
			}
			continue
		}
		if coupon.UseGoodsType == 3 { // 3指定商品可用
			if php2go.InArray(gconv.Int(item.Id), ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
		if coupon.UseGoodsType == 4 { // 4指定商品不可用
			if !php2go.InArray(gconv.Int(item.Id), ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
		if coupon.UseGoodsType == 5 { // 5指定店铺可用
			if php2go.InArray(item.StoreId, ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
		if coupon.UseGoodsType == 6 { // 6指定店铺不可用
			if !php2go.InArray(item.StoreId, ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
	}
	// 排除不可用的
	if coupon.ExcludeGoodsIds != nil {
		excludeGoodsIds := coupon.ExcludeGoodsIds.Slice()
		for k, item := range canUseOrderSubs {
			if php2go.InArray(item.GoodsId, excludeGoodsIds) {
				canUseOrderSubs = append(canUseOrderSubs[:k], canUseOrderSubs[k+1:]...)
			}
		}
	}
	// 统计总可用子订单的总金额
	var canUseTotalPrice int64 = 0
	// 统计总可用子订单的总件数
	var canUseTotalNum int64 = 0

	for _, item := range canUseOrderSubs {
		canUseTotalPrice += item.TotalPrice
		canUseTotalNum += item.Num
	}
	// 判断是否有门槛
	if coupon.IsThreshold == 1 {
		// 判断是否足够门槛
		switch coupon.CouponType {
		case 1, 2:
			// 满金额
			if coupon.ThresholdMoney > canUseTotalPrice {
				// 不符合，返回空
				return []OrderReq.OrderSubCoupon{}
			}
			break
		case 3, 4: // 满件
			if int64(coupon.ThresholdNum) > canUseTotalNum {
				// 不符合，返回空
				return []OrderReq.OrderSubCoupon{}
			}
			break
		}
	} else {
		// 无门槛时，需要把 ThresholdMoney ThresholdNum 清 0
		coupon.ThresholdMoney = 0
		coupon.ThresholdNum = 0
	}

	switch coupon.CouponType {
	case 1, 3: // 1满金额减；3满件减
		for k, item := range canUseOrderSubs {
			canUseOrderSubs[k].Discount = int64(tools.FloatRound(float64(item.TotalPrice)/float64(canUseTotalPrice)*(float64(coupon.DiscountMoney)/100.00), 2) * 100.00)
			canUseOrderSubs[k].Paid = item.TotalPrice - canUseOrderSubs[k].Discount
			// 如果优惠金额大于订单金额，修正
			if canUseOrderSubs[k].Paid < 1 {
				canUseOrderSubs[k].Paid = 0
				canUseOrderSubs[k].Discount = item.TotalPrice
			}
		}
		break
	case 2, 4: // 2满金额折；4满件折
		for k, item := range canUseOrderSubs {
			canUseOrderSubs[k].Paid = int64(tools.FloatRound(float64(item.TotalPrice)*(float64(coupon.DiscountRatio)/10000.00), 2))
			canUseOrderSubs[k].Discount = item.TotalPrice - canUseOrderSubs[k].Paid
		}
		break
	}
	// 返回使用了优惠券的子订单集合，方便后续做日志
	return canUseOrderSubs
}

// 按商家检查
func CheckStore(ctx context.Context, parames *OrderReq.SubmitItem, useCouponList []*MemberResp.MemberCoupon) (*OrderReq.CheckSubmitItem, error) {
	if len(parames.GoodsList) < 1 {
		return nil, errors.New("商品为空")
	}
	var totalPrice int64 = 0
	var results = OrderReq.CheckSubmitItem{}
	results.StoreId = parames.StoreId
	for _, goods := range parames.GoodsList {
		data, err := checkGoods(ctx, goods, parames.StoreId)
		if err != nil {
			return nil, err
		}
		results.GoodsList = append(results.GoodsList, data)
		// 计算总价
		totalPrice += int64(goods.GoodsNum) * data.Options[0].SellPrice
		// 计算运费

	}
	results.GoodsKey = getGoodsKeyString(results.GoodsList)

	// 检测活动

	// 检测优惠券
	var useOrderSubs []OrderReq.OrderSubCoupon
	for _, item := range useCouponList {
		useOrderSubs = append(useOrderSubs, calcCouponOne(results.GoodsList, item)...)
	}
	results.UseCouponOrderSubs = useOrderSubs

	// 检测发票
	// 原订单总价（商品合计，未包含任何优惠）单位分
	results.OriginalTotalPrice = totalPrice
	// 计算总价 减去全部优惠
	for _, item := range useOrderSubs {
		totalPrice -= item.Discount
	}
	results.TotalPrice = totalPrice
	return &results, nil
}

func GetOrderNumByMemberIdAndStatus(ctx context.Context, memberId int, status []int) int {
	count, countErr := toolsDb.GetUnSafaTableAddDeleteWhere(
		ctx,
		"order").Where(
		"delete_at<1 AND member_id=? AND status IN (?)",
		memberId,
		status,
	).Fields(
		"1").Count()
	if countErr != nil {
		return 0
	}

	return count
}
func GetOrderAftersaleNumByMemberId(ctx context.Context, memberId int) int {
	count, countErr := toolsDb.GetUnSafaTableAddDeleteWhere(
		ctx,
		"order").As("o").LeftJoin("order_sub os", "o.id = os.order_id").Where(
		"o.delete_at<1 AND o.member_id=? AND os.refund_status IN (?)",
		memberId,
		[]int{
			1,
			2,
			3,
		},
	).Fields(
		"1").Count()
	if countErr != nil {
		return 0
	}

	return count
}

// 判断是否是当前会员订单
func IsMyOrder(ctx context.Context, orderId, memberId int) bool {
	count, err := toolsDb.GetUnSafaTable(ctx, "order").Where(
		"id = ? AND member_id = ?", orderId,
		memberId,
	).Fields("1").Count()
	if err != nil {
		return false
	}

	return count > 0
}

func GetOrderModel(ctx context.Context, orderId int) (*entity.Order, error) {
	var oModel *entity.Order
	err := toolsDb.GetUnSafaTableAddDeleteWhere(
		ctx,
		"order").Where(
		"delete_at<1 AND id=?",
		orderId,
	).Scan(&oModel)
	if err != nil {
		return nil, err
	}

	return oModel, nil
}

// 获取预下单可使用的优惠券，提供给 doCreateByGroup 方法使用
func getCreateAvailableUseCoupon(ctx context.Context, memberId int, goodss []*OrderResp.Goodss) ([]OrderReq.OrderSubCoupon, error) {
	// 取出我未使用的优惠券
	cList, err := CouponService.GetMyAvailable(ctx, memberId)
	if err != nil {
		return nil, err
	}
	var siList []*OrderReq.OrderSubItem
	for _, item := range goodss {
		siList = append(siList, &OrderReq.OrderSubItem{
			Details:    item.Details,
			Hash:       guid.S(),
			Total:      item.BuyNum,
			TotalPrice: item.Paid,
			OptionId:   int(item.Options[0].Id),
		})
	}
	// 判断符合当前商品的优惠券
	var useOrderSubs []OrderReq.OrderSubCoupon
	for _, item := range cList {
		tmps := calcCouponOne(siList, item)
		for _, t := range tmps {
			// 如果没有优惠金额，说明优惠券不能使用
			if t.Discount > 0 {
				useOrderSubs = append(useOrderSubs, t)
			}
		}
	}
	return useOrderSubs, nil
}

func GetExpressBySn(sn string) ([]*OrderResp.ExpressItem, error) {
	var list []*OrderResp.ExpressItem
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-07 11:07:13",
		Content: "已签收,感谢使用顺丰,期待再次为您服务",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-07 08:12:12",
		Content: "快件交给郑卫*，正在派送途中",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-07 06:52:56",
		Content: "快件到达 【中山港口水禾园营业部】",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-06 23:55:53",
		Content: "快件到达 【中山东升集散中心】",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-06 23:55:53",
		Content: "快件在【中山东升集散中心】已装车，准备发往 【中山港口水禾园营业部】",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-06 21:17:36",
		Content: "快件在【珠海界涌集散中心】已装车，准备发往 【中山东升集散中心】",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-06 21:17:36",
		Content: "快件到达 【珠海界涌集散中心】",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-06 19:38:09",
		Content: "快件在【珠海香洲景园路营业部】已装车，准备发往 【珠海界涌集散中心】",
	})
	list = append(list, &OrderResp.ExpressItem{
		Time:    "2017-07-06 18:05:01",
		Content: "顺丰速运 已收取快件",
	})

	return list, nil
}
